package com.witframework.util;

import java.io.OutputStream;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;
import javax.servlet.ServletConfig;

/** @pdOid 676cbc8f-5d26-4ec4-9762-7164dc5846ae */
public class FileSystemHandler {
   /** @pdOid 466055b1-5b15-47a2-aa3a-e587061a266e */
   private static String VERSION_NR = "1.0";
   /** The compression level for zip file creation (0-9)
    * 
    * 
    * @pdOid 9bfbf391-2010-4851-a96e-1f1b587e699e */
   private static final int COMPRESSION_LEVEL = 1;
   
   /** @param file
    * @exception IOException
    * @pdOid 33cf4b2e-3651-496f-a12a-6300b1bc408e */
   private void downLoadFile(String file) throws IOException {
     PrintWriter out=response.getWriter();
     File f = new File(file);
     if (f.exists() && f.canRead()) {
       response.setContentType("application/octet-stream");
       response.setHeader("Content-Disposition", "attachment;filename=\""+new String(f.getName().getBytes(),"ISO-8859-1")+"\"");
       response.setContentLength( (int) f.length());
       BufferedInputStream fileInput = new BufferedInputStream(new FileInputStream(f));
       byte buffer[] = new byte[8 * 1024];
       out.flush();
       OutputStream out_s = new Writer2Stream(out);
       copyStreamsWithoutClose(fileInput, out_s, buffer);
       fileInput.close();
       out_s.flush();
     }
     else {
       request.setAttribute("dir", f.getParent());
       request.setAttribute("error", "File " + f.getAbsolutePath() +
                            " does not exist or is not readable on the server");
     }
   }
   
   /** @param files
    * @exception IOException
    * @pdOid 93d955ac-c42b-4e04-a720-da8500f0cc88 */
   private void downLoadZipFile(String[] files) throws IOException {
     PrintWriter out=response.getWriter();
     Vector v = expandFileList(files, false);
     if (v.size() == 0) {
       request.setAttribute("error", "No files selected");
     }
     else {
       File dir_file = new File("" + request.getAttribute("dir"));
       int dir_l = dir_file.getAbsolutePath().length();
       response.setContentType("application/zip");
       response.setHeader("Content-Disposition", "attachment;filename=\"rename_me.zip\"");
       out.flush();
       ZipOutputStream zipout = new ZipOutputStream(new Writer2Stream(out));
       zipout.setComment("Created by DownLoadFileUtils v. " + VERSION_NR);
       zipout.setLevel(COMPRESSION_LEVEL);
       for (int i = 0; i < v.size(); i++) {
         File f = (File) v.get(i);
         if (f.canRead()) {
           zipout.putNextEntry(new ZipEntry(f.getAbsolutePath().substring(dir_l + 1)));
           BufferedInputStream fr = new BufferedInputStream(new FileInputStream(f));
           byte buffer[] = new byte[0xffff];
           copyStreamsWithoutClose(fr, zipout, buffer);
           fr.close();
           zipout.closeEntry();
         }
       }
       zipout.finish();
       out.flush();
     }
   
   }
   
   /** @pdOid c8c53e67-4db0-483a-a3ad-2fcfb8e516f1 */
   protected HttpServletRequest request;
   /** @pdOid 6ad4e503-8fab-4174-b14f-33bfe6cc7133 */
   protected HttpServletResponse response;
   
   /** @param files 
    * @param inclDirs
    * @pdOid 5a6f2173-5667-4b56-affd-1bc406059346 */
   static Vector expandFileList(String[] files, boolean inclDirs) {
     Vector v = new Vector();
     if (files == null) {
       return v;
     }
     for (int i = 0; i < files.length; i++) {
       try {
         v.add(new File(URLDecoder.decode(files[i], "gb2312"), "gb2312"));
       }
       catch (UnsupportedEncodingException ex) {
       }
     }
     for (int i = 0; i < v.size(); i++) {
       File f = (File) v.get(i);
       if (f.isDirectory()) {
         File[] fs = f.listFiles();
         for (int n = 0; n < fs.length; n++) {
           v.add(fs[n]);
         }
         if (!inclDirs) {
           v.remove(i);
           i--;
         }
       }
     }
     return v;
   }
   
   /** 检查给定的文件名是否有打包文件后缀
    * 
    * @param name String
    * @param gz boolean
    * @return boolean
    * 
    * @pdOid 6f118853-c2ef-4943-825a-2485fe17258b */
   static boolean isPacked(String name, boolean gz) {
     return (name.toLowerCase().endsWith(".zip") || name.toLowerCase().endsWith(".jar") ||
             (gz && name.toLowerCase().endsWith(".gz")) || name.toLowerCase().endsWith(".war"));
   }
   
   /** @param in 
    * @param out 
    * @param buffer
    * @exception IOException
    * @pdOid 8670e525-2e73-42af-9454-ab9d105d121b */
   static void copyStreamsWithoutClose(InputStream in, OutputStream out, byte[] buffer) throws IOException {
     int b;
     while ( (b = in.read(buffer)) != -1) {
       out.write(buffer, 0, b);
     }
   }
   
   /** Returns the Mime Type of the file, depending on the extension of the filename
    * 
    * 
    * @param fName
    * @pdOid 4c73f17e-a293-41b7-a5d1-4b6a62062238 */
   public static String getMimeType(String fName) {
     fName = fName.toLowerCase();
     if (fName.endsWith(".jpg") || fName.endsWith(".jpeg") || fName.endsWith(".jpe")) {
       return "image/jpeg";
     }
     else if (fName.endsWith(".gif")) {
       return "image/gif";
     }
     else if (fName.endsWith(".pdf")) {
       return "application/pdf";
     }
     else if (fName.endsWith(".htm") || fName.endsWith(".html") || fName.endsWith(".shtml")) {
       return "text/html";
     }
     else if (fName.endsWith(".avi")) {
       return "video/x-msvideo";
     }
     else if (fName.endsWith(".mov") || fName.endsWith(".qt")) {
       return "video/quicktime";
     }
     else if (fName.endsWith(".mpg") || fName.endsWith(".mpeg") || fName.endsWith(".mpe")) {
       return "video/mpeg";
     }
     else if (fName.endsWith(".zip")) {
       return "application/zip";
     }
     else if (fName.endsWith(".tiff") || fName.endsWith(".tif")) {
       return "image/tiff";
     }
     else if (fName.endsWith(".rtf")) {
       return "application/rtf";
     }
     else if (fName.endsWith(".mid") || fName.endsWith(".midi")) {
       return "audio/x-midi";
     }
     else if (fName.endsWith(".xl") || fName.endsWith(".xls") || fName.endsWith(".xlv") || fName.endsWith(".xla")
              || fName.endsWith(".xlb") || fName.endsWith(".xlt") || fName.endsWith(".xlm") || fName.endsWith(".xlk")) {
       return "application/excel";
     }
     else if (fName.endsWith(".doc") || fName.endsWith(".dot")) {
       return "application/msword";
     }
     else if (fName.endsWith(".png")) {
       return "image/png";
     }
     else if (fName.endsWith(".xml")) {
       return "text/xml";
     }
     else if (fName.endsWith(".svg")) {
       return "image/svg+xml";
     }
     else if (fName.endsWith(".mp3")) {
       return "audio/mp3";
     }
     else if (fName.endsWith(".ogg")) {
       return "audio/ogg";
     }
     else {
       return "text/plain";
     }
   }
   
   /** @param req 
    * @param res 
    * @param cfg
    * @pdOid ce74a4ff-8108-46a9-aa5e-4ecdc4e685f9 */
   public FileSystemHandler(HttpServletRequest req, HttpServletResponse res, ServletConfig cfg) {
    this.request = req;
    this.response = res;
   }
   
   /** @exception FileNotFoundException
    * @exception IOException
    * @pdOid 7d3adbc7-357c-432c-a1f8-5c66ba33f1d2 */
   public void doView() throws FileNotFoundException, IOException {
     PrintWriter out=response.getWriter();
     File f = new File(request.getParameter("file"));
     if (f.exists() && f.canRead()) {
       if (isPacked(f.getName(), false)) {
         //If zipFile, do nothing here
       }
       else {
         String mimeType = getMimeType(f.getName());
         response.setContentType(mimeType);
         if (mimeType.equals("text/plain")) {
           response.setHeader("Content-Disposition", "inline;filename=\"temp.txt\"");
         }
         else {
           response.setHeader("Content-Disposition", "inline;filename=\"" + f.getName() + "\"");
         }
         BufferedInputStream fileInput = new BufferedInputStream(new FileInputStream(f));
         byte buffer[] = new byte[8 * 1024];
         out.flush();
         OutputStream out_s = new Writer2Stream(out);
         copyStreamsWithoutClose(fileInput, out_s, buffer);
         fileInput.close();
         out_s.flush();
       }
     }
     else {
       request.setAttribute("dir", f.getParent());
       request.setAttribute("error", "File " + f.getAbsolutePath() +
                            " does not exist or is not readable on the server");
     }
   }
   
   /** @exception IOException
    * @pdOid 6e2e3c23-9a6b-4112-a216-79f721f32c4c */
   public void doDownload() throws IOException {
     String[] files=request.getParameterValues("file");
     if(files!=null&&files.length>1){
       downLoadZipFile(files);
     }else if(files!=null&&files.length==1){
       downLoadFile(files[0]);
     }
   }

   /** Wrapperclass to wrap an OutputStream around a Writer
    * 
    * 
    * @pdOid 5bb89b99-3df6-41d3-8fe4-31ffa20dc811 */
   class Writer2Stream extends java.io.OutputStream {
      /** @pdOid 1371d873-a4f2-42c7-b9f3-8ee5b5d1bf61 */
      Writer out;
      
      /** @param w
       * @pdOid 28bc1000-dffd-4c68-9f7f-f1af5b822743 */
      Writer2Stream(Writer w) {
        super();
        out = w;
      }
      
      /** @param i
       * @exception IOException
       * @pdOid 552f6e9d-c8f8-4db1-8f97-fb786a4e6c8b */
      public void write(int i) throws IOException {
        out.write(i);
      }
      
      /** @param b
       * @exception IOException
       * @pdOid 7f6a9343-6dec-4438-8631-ed7a5ded02f8 */
      public void write(byte[] b) throws IOException {
        for (int i = 0; i < b.length; i++) {
          int n = b[i];
          //Convert byte to ubyte
          n = ( (n >>> 4) & 0xF) * 16 + (n & 0xF);
          out.write(n);
        }
      }
      
      /** @param b 
       * @param off 
       * @param len
       * @exception IOException
       * @pdOid b949c61c-3606-4d5b-a13d-c6aefbc44ee3 */
      public void write(byte[] b, int off, int len) throws IOException {
        for (int i = off; i < off + len; i++) {
          int n = b[i];
          n = ( (n >>> 4) & 0xF) * 16 + (n & 0xF);
          out.write(n);
        }
      }
   
   }

}